package han.chensing.latos.game.input;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.math.Vector2;

import han.chensing.latos.V;

public class TouchContainer extends InputAdapter implements Runnable{

    private final Touch[] touches;
    private final Vector2 tempVector2=new Vector2();
    private volatile boolean needsUpdateDistance=false;
    private final boolean multiThread;

    public TouchContainer(boolean multiThread){
        this.touches=new Touch[Gdx.input.getMaxPointers()];
        this.multiThread=multiThread;
        for(int i=0;i<touches.length;i++)
            touches[i]=new Touch(i);
        if (multiThread)new Thread(this).start();
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        updateTouch(pointer,screenX,screenY,true,true,false);
        return true;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        updateTouch(pointer,screenX,screenY,false,false,false);
        return true;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        if (multiThread)return false;
        updateTouch(pointer,screenX,screenY,false,true,true);
        return true;
    }

    private void updateTouch(int index, int fx, int fy,boolean start, boolean touched,boolean updateDistance){
        tempVector2.x=fx;
        tempVector2.y=fy;
        Vector2 project = V.globalViewport.unproject(tempVector2);
        int x=(int) project.x;
        int y=(int) project.y;
        Touch touch = touches[index];
        touch.touched=touched;
        if (updateDistance&&needsUpdateDistance)
            touch.dragDistance+=(float) Math.sqrt(
                    Math.pow(x-touch.startX,2)+Math.pow(y-touch.startY,2));
        touch.x=x;
        touch.y=y;
        if (start){
            touch.startX= touch.x;
            touch.startY= touch.y;
            touch.dragDistance=0;
        }
        if (!touched)
            touch.cleanAppends();
    }

    public Touch[] getTouches() {
        return touches;
    }

    public boolean isNeedsUpdateDistance() {
        return needsUpdateDistance;
    }

    public void setNeedsUpdateDistance(boolean needsUpdateDistance) {
        this.needsUpdateDistance = needsUpdateDistance;
    }

    @Override
    public void run() {
        while (V.running){
            for(int i=0;i<touches.length;i++){
                int x = Gdx.input.getX(i);
                int y = Gdx.input.getY(i);
                boolean touched = Gdx.input.isTouched(i);
                updateTouch(i,x,y,false,touched,true);
            }
        }
    }

    public static class Touch{
        private final int num;
        private int x;
        private int y;
        private int startX;
        private int startY;
        private float dragDistance;
        private boolean touched;
        private boolean touchTapHandled;
        private boolean touchHoldHandled;
        public Touch(int num){
            this.num=num;
            this.x=0;
            this.y=0;
            this.startX=0;
            this.startY=0;
            this.dragDistance=0;
            this.touched=false;
            this.touchTapHandled =false;
            cleanAppends();
        }
        public int getX() {
            return x;
        }
        public void setX(int x) {
            this.x = x;
        }
        public int getY() {
            return y;
        }
        public void setY(int y) {
            this.y = y;
        }
        public boolean isTouched() {
            return touched;
        }
        public void setTouched(boolean touched) {
            this.touched = touched;
        }
        public void cleanAppends(){
            touchTapHandled =false;
            touchHoldHandled=false;
            dragDistance=0;
        }
        public float getDragDistance() {
            return dragDistance;
        }
        public void setDragDistance(float dragDistance) {
            this.dragDistance = dragDistance;
        }
        public int getStartX() {
            return startX;
        }
        public void setStartX(int startX) {
            this.startX = startX;
        }
        public int getStartY() {
            return startY;
        }
        public void setStartY(int startY) {
            this.startY = startY;
        }
        public boolean isTouchTapHandled() {
            return touchTapHandled;
        }
        public void setTouchTapHandled(boolean touchTapHandled) {
            this.touchTapHandled = touchTapHandled;
        }
        public int getNum() {
            return num;
        }
        public boolean isTouchHoldHandled() {
            return touchHoldHandled;
        }
        public void setTouchHoldHandled(boolean touchHoldHandled) {
            this.touchHoldHandled = touchHoldHandled;
        }
    }
}
